import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
  Logger,
} from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  private readonly logger = new Logger('HTTP');

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    const response = context.switchToHttp().getResponse();
    const startTime = Date.now();
    const clientIp = (request.headers['x-forwarded-for'] as string)
      ? (request.headers['x-forwarded-for'] as string).split(',')[0]
      : request.ip || request.connection.remoteAddress;

    return next.handle().pipe(
      tap({
        next: () => {
          const statusCode = response.statusCode;
          const duration = Date.now() - startTime;
          this.logger.log(
            `ClientIP: ${clientIp}, Response for ${request.method} ${request.url} with Status Code: ${statusCode} took ${duration}ms`,
          );
        },
        error: (error) => {
          const statusCode = error.status;
          const duration = Date.now() - startTime;
          this.logger.error(
            `ClientIP: ${clientIp}, Error on ${request.method} ${request.url} with Status Code: ${statusCode}: ${error.message} after ${duration}ms`,
          );
        },
      }),
      catchError((error) => {
        return throwError(() => error);
      }),
    );
  }
}
